﻿using Demo.PetaPoco.Application.DbContexts;
using Demo.PetaPoco.Application.Dtos.Dept;
using Demo.PetaPoco.Application.Dtos.User;
using Demo.Domains.Entities.Sys;
using Microsoft.Extensions.DependencyInjection;
using PmSoft.Core;
using PmSoft.Data.Abstractions;
using PmSoft.Data.PetaPoco;
using PmSoft.Core.Extensions;
using PmSoft.Core.Domain.Auth;

namespace Demo.PetaPoco.Application.Services.User;

/// <summary>
/// 用户服务类，提供对用户数据的操作，包括创建、更新、查询等功能。
/// </summary>
[Inject(ServiceLifetime.Scoped)]
public class UserService(UserRepository userRepository,
	UserRoleRepository userRoleRepository,
		ICachedEntityLoader<AppDbContext> cachedEntityLoader,
		PetaPocoUnitOfWork<AppDbContext> unitOfWork)
{

	/// <summary>
	/// 创建新用户。
	/// </summary>
	/// <param name="createIn">用户创建模型，包含用户的基本信息。</param>
	/// <returns>异步操作</returns>
	/// <exception cref="Exception">抛出异常如果创建失败。</exception>
	public virtual async Task CreateAsync(UserCreateModel createIn)
	{
		// 密码加密
		string encodedPassword = UserPasswordHelper.EncodePassword(createIn.Password, UserPasswordFormat.MD5);
		var user = createIn.MapTo<UserCreateModel, SysUser>();
		user.Password = encodedPassword;
		if (!createIn.Mobile.IsNullOrEmpty() && await userRepository.ExistsByMobileAsync(user.Mobile))
			throw new PmSoftException("手机号码已存在");
		if (!createIn.Email.IsNullOrEmpty() && await userRepository.ExistsByEmailAsync(user.Email))
			throw new PmSoftException("电子邮箱已存在");
		//执行事务
		await unitOfWork.ExecuteInTransactionAsync(async () =>
		{
			// 插入新用户到数据库
			await userRepository.InsertAsync(user);
			//下面写事务中其他表操作
		});

	}

	/// <summary>
	/// 更新现有用户的信息。
	/// </summary>
	/// <param name="editIn">用户编辑模型，包含用户的更新信息。</param>
	/// <returns>异步操作</returns>
	public async Task UpdateAsync(UserEditModel editIn)
	{
		if (!editIn.UserId.HasValue)
			throw new ArgumentNullException(nameof(editIn.UserId));

		var user = await userRepository.GetAsync(editIn.UserId.Value);

		if (user == null)
			throw new ArgumentNullException(nameof(user));  // 用户不存在时抛出异常

		// 使用编辑模型更新用户信息
		user = editIn.MapTo(user, setter =>
		{
			setter.Ignore(dest => dest.Id);  // 忽略用户ID
			if (editIn.Password.IsNullOrEmpty())
				setter.Ignore(dest => dest.Password);  // 如果没有提供密码，则忽略密码字段
		});

		// 如果提供了密码，则进行密码加密
		if (!editIn.Password.IsNullOrEmpty())
		{
			string encodedPassword = UserPasswordHelper.EncodePassword(editIn.Password, UserPasswordFormat.MD5);
			user.Password = encodedPassword;
		}

		// 更新数据库中的用户信息
		await userRepository.UpdateAsync(user);
	}

	/// <summary>
	/// 根据用户ID获取单个用户信息。
	/// </summary>
	/// <param name="id">用户ID。</param>
	/// <returns>用户DTO。</returns>
	/// <exception cref="ArgumentNullException">如果用户不存在，则抛出此异常。</exception>
	public async ValueTask<UserDetailDto> GetUserAsync(int id)
	{
		var user = await userRepository.GetAsync(id);
		if (user == null)
			throw new ArgumentNullException(nameof(user));  // 如果用户不存在，抛出异常

		var userDto = user.MapTo<SysUser, UserDetailDto>();
		var dept = await cachedEntityLoader.GetEntityAsync<SysDept, int>(userDto.DeptId);
		userDto.Dept = dept?.MapTo<SysDept, DeptDto>();  // 加载用户的部门信息
		userDto.DeptName = dept?.Name;  // 加载用户的部门名称
		return userDto;
	}


	public async ValueTask<AuthedUserInfoDto> GetAuthedUserInfoAsync(IAuthedUser authUser)
	{
		var user = await userRepository.GetAsync(authUser.UserId);
		if (user == null)
			throw new ArgumentNullException(nameof(user));  // 如果用户不存在，抛出异常

		var userDto = user.MapTo<SysUser, AuthedUserInfoDto>(setter =>
		{

			setter.Map(dest => dest.UserId, src => src.Id);
			setter.Map(dest => dest.Username, src => src.Mobile);
			setter.Map(dest => dest.RealName, src => src.Name);
		});
		var userRoles = await userRoleRepository.GetUserRolesAsync(userDto.UserId);
		var roles = await cachedEntityLoader.GetEntitiesByIdsAsync<SysRole, int>(userRoles.Select(m => m.RoleId));
		userDto.Roles = roles.Select(m => m.Code).ToArray();

		return userDto;
	}

	/// <summary>
	/// 获取指定单位下的所有用户列表。
	/// </summary>
	/// <param name="deptId">单位ID。</param>
	/// <returns>用户列表。</returns>
	public async ValueTask<IEnumerable<UserDto>> GetUsersAsync(int deptId)
	{
		var users = await userRepository.GetUsersAsync(deptId);
		return await users.Select(user => user.MapTo<SysUser, UserDto>())
			.WithRelatedAsync(                                // 加载部门信息
				foreignKeySelector: user => user.DeptId,
				loadRelatedEntities: cachedEntityLoader.GetEntitiesByIdsAsync<SysDept, int>,
				attachAction: (user, dept) => user.Dept = dept?.MapTo<SysDept, DeptDto>()
			).WithRelatedAsync(                                // 加载部门信息
				foreignKeySelector: user => user.DeptId,
				loadRelatedEntities: cachedEntityLoader.GetEntitiesByIdsAsync<SysDept, int>,
				attachAction: (user, dept) => user.Dept = dept?.MapTo<SysDept, DeptDto>()
			);
	}

	/// <summary>
	/// 获取用户的分页列表。
	/// </summary>
	/// <param name="query">用户查询条件。</param>
	/// <returns>分页用户DTO列表。</returns>
	public async ValueTask<IPagedList<UserDto>> UserPagingAsync(UserQuery query)
	{
		var pagedUsers = await userRepository.UserPagingAsync(query);

		return await pagedUsers
			.ToPagedDtoAsync(async (user) =>
			{
				await cachedEntityLoader.GetEntitiesByIdsAsync<SysDept, int>(new List<int> { 1 });
				return user.MapTo<SysUser, UserDto>();
			})   // 基本信息转换
			.WithRelatedAsync(                                // 加载部门信息
				foreignKeySelector: user => user.DeptId,
				loadRelatedEntities: cachedEntityLoader.GetEntitiesByIdsAsync<SysDept, int>,
				attachAction: (user, dept) => user.DeptName = dept.Name
			).WithRelatedAsync(                                // 加载部门信息
				foreignKeySelector: user => user.DeptId,
				loadRelatedEntities: cachedEntityLoader.GetEntitiesByIdsAsync<SysDept, int>,
				attachAction: (user, dept) => user.Dept = dept?.MapTo<SysDept, DeptDto>()
			);
	}

	public async Task DeleteAsync(int userId)
	{
		await userRepository.DeleteByEntityIdAsync(userId);
	}
}
